// Land.cpp: implementation of the Land class.
//
//////////////////////////////////////////////////////////////////////

#include "Land.h"

// Height color map
static sgVec4 heightColors[NUM_MAP_COLS] = { 
 { 0.0f, 0.1f, 0.0f, 1.0f },
 { 0.0f, 0.1f, 0.1f, 1.0f },
 { 0.0f, 0.1f, 0.2f, 1.0f },
 { 0.0f, 0.2f, 0.2f, 1.0f },
 { 0.0f, 0.3f, 0.2f, 1.0f },
 { 0.0f, 0.4f, 0.2f, 1.0f },
 { 0.0f, 0.5f, 0.2f, 1.0f },
 { 0.0f, 0.6f, 0.2f, 1.0f },
 { 0.0f, 0.7f, 0.2f, 1.0f },
 { 0.0f, 0.8f, 0.2f, 1.0f },
 { 0.0f, 0.9f, 0.2f, 1.0f },
 { 0.0f, 1.0f, 0.2f, 1.0f },
 { 0.6f, 0.9f, 0.4f, 1.0f },
 { 0.6f, 0.8f, 0.5f, 1.0f },
 { 1.0f, 1.0f, 0.6f, 1.0f },
 { 1.0f, 1.0f, 0.5f, 1.0f },
 { 1.0f, 1.0f, 0.4f, 1.0f },
 { 1.0f, 1.0f, 0.3f, 1.0f },
 { 1.0f, 1.0f, 0.2f, 1.0f },
 { 1.0f, 1.0f, 0.1f, 1.0f },
 { 1.0f, 0.9f, 0.0f, 1.0f },
 { 1.0f, 0.8f, 0.0f, 1.0f },
 { 1.0f, 0.7f, 0.0f, 1.0f },
 { 1.0f, 0.6f, 0.0f, 1.0f },
 { 1.0f, 0.5f, 0.0f, 1.0f },
 { 1.0f, 0.4f, 0.0f, 1.0f },
 { 1.0f, 0.3f, 0.0f, 1.0f },
 { 1.0f, 0.2f, 0.0f, 1.0f },
 { 1.0f, 0.1f, 0.0f, 1.0f },
 { 1.0f, 0.0f, 0.0f, 1.0f },
 { 0.9f, 0.4f, 0.0f, 1.0f },
 { 0.8f, 0.4f, 0.0f, 1.0f },
 { 0.7f, 0.4f, 0.0f, 1.0f },
 { 0.6f, 0.4f, 0.0f, 1.0f },
 { 0.6f, 0.3f, 0.0f, 1.0f },
 { 0.6f, 0.2f, 0.0f, 1.0f },
 { 0.6f, 0.1f, 0.0f, 1.0f },
 { 0.5f, 0.2f, 0.0f, 1.0f },
 { 0.4f, 0.2f, 0.0f, 1.0f },
 { 0.3f, 0.2f, 0.0f, 1.0f },
 { 0.2f, 0.2f, 0.0f, 1.0f },
 { 0.1f, 0.2f, 0.0f, 1.0f },
 { 0.2f, 0.0f, 0.0f, 1.0f },
 { 0.1f, 0.0f, 0.0f, 1.0f }
 };
 
 static sgVec4 objectsColors[3] = { 
 { 0.1f, 0.3f, 0.0f, 1.0f },      // forest
 { 0.2f, 0.6f, 0.6f, 1.0f },		 // river
 { 0.5f, 0.4f, 0.2f, 1.0f }      // mud
 };
 
 static sgVec4 pixelColors[3] = { 
 { 1.0f, 0.0f, 1.0f, 1.0f },      // forest
 { 0.0f, 0.0f, 1.0f, 1.0f },		 // river
 { 1.0f, 0.0f, 0.0f, 1.0f }      // mud
 };
 
 static sgVec4 wire_colour = { 0.0f, 1.0f, 0.0f, 1.0f } ;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Land::Land(char dem_filename[],char obj_filename[],LoadingInfo* li)
{
FILE* f;
char fileRow[FILE_ROW_STRING_LENGTH];
char ch1,ch2;
int c = 0;
int r = 0;
int x = 0;
int y = 0;
int gr = 0;
int i = 0;
int j = 0;
bmp = NULL;

this->li = li;

float file_read_progress = 0.0f;

 /* LOADER */
if((f = fopen(dem_filename,"r")) != NULL)
		{
		/* jump beyond header */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);

		/* read the number of columns */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		sscanf(fileRow,"%c%c%d",&ch1,&ch2,&c);

		/* read the number of rows */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		sscanf(fileRow,"%c%c%d",&ch1,&ch2,&r);

		/* read the x_start_coord (and  stores it in x)  */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		sscanf(fileRow,"%d",&x);

		/* read the y_start_coord (and  stores it in y) */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		sscanf(fileRow,"%d",&y);

		/* read the grid step */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);
		sscanf(fileRow,"%d",&gr);
		
		/* allocate a matrix of r * c */
		this->exceeding_r = (r - 1) % LAND_TRIANGLE_GRID_SIZE;
		this->exceeding_c = (c - 1) % LAND_TRIANGLE_GRID_SIZE; 

		newMatrix(landMap,r,c,_i,sgFloat);

		//printf("\nMAP ROWS: %d MAP COLS: %d\n",r,c);

		/* jump over another line */
		fgets(fileRow,FILE_ROW_STRING_LENGTH,f);

		/* read the lines containing the height values */
		/* This matrix is filled per columns, from the bottom to the top,
		   and from the left to the right. So data in memory have the 'same'
		   position (each other) than in the real world...*/
		while(fgets(fileRow,FILE_ROW_STRING_LENGTH,f) != NULL)
			{
			if(j < r)
				{
				sscanf(fileRow,"%f",&(this->landMap[r-j-1][i]));
				j++;
				}
			else
				{
				j = 0;
				i += 1;
				sscanf(fileRow,"%f",&(this->landMap[r-j-1][i]));
				j++;
				}
			file_read_progress = (float)(j * i) / (float)r*(float)c; 
			doCritical(li->mapProgress += 0.15f*file_read_progress , li->cs);
			}

		/* close the file stream  */
		fclose(f);
		}
	else
		{
		printf("Cannot open .DEM file %s for reading.\n",dem_filename);
		exit(0);
		}

//printf("\nMAP LOADED\n");
//printMatrix(landMap,r,c);

/* copy the temp values into the class ones */
strcpy(this->dem_filename,dem_filename);
strcpy(this->obj_filename,obj_filename);

this->mapCols = c;
this->mapRows = r;

this->gridStep = gr;

this->gridThinFactor = 1;

this->x_start_coord = x*10.0f;
this->y_start_coord = y*10.0f;


this->triangle_grid_size = LAND_TRIANGLE_GRID_SIZE;

// check if dimension is smaller (should never happen!!!)

// leaf side dimension (the same for X and Y, 'cause it's a square)
this->tile_size = this->triangle_grid_size * this->gridStep;

// now I know each leaf's dimension, and the map size.
// Calculate how many leaves there'll be.

// with if(1) if the map has a non-leaf-demension-multiple dimension
// all the extra (sub-dimensioned) tiles will be discarded...

if( ((this->mapCols - 1) % (this->triangle_grid_size)) == 0)
	{
	this->tile_grid_columns = (int)( (this->mapCols - 1) / (this->triangle_grid_size)); 
	}
else
	{
	this->tile_grid_columns = (int)( (this->mapCols - 1) / (this->triangle_grid_size) ) + 1;
	}
if( ((this->mapRows - 1) % (this->triangle_grid_size)) == 0)
	{
	this->tile_grid_rows = (int)( (this->mapRows - 1) / (this->triangle_grid_size)); 
	}
else
	{
	this->tile_grid_rows = (int)( (this->mapRows - 1) / ( this->triangle_grid_size) ) + 1;
	}
/* By now the map has got it's bottom left corner over the origin... but
   I want it's center point over the origin... so that's the traslation 
   that will be applied (well, the inverse of this) */
this->online_terrain_range_x = (float)(mapCols-1) * gridStep / 2.0f;
this->online_terrain_range_y = (float)(mapRows-1) * gridStep / 2.0f;

// Extern tiles dimensions 
this->exceeding_c = (this->mapCols-1) % (this->triangle_grid_size);
this->exceeding_r = (this->mapRows-1) % (this->triangle_grid_size);

// lambda factor for texture mapping
//this->lambda = this->tile_size / (LAND_TEXTURES_LAMBDA_MULT_FACTOR * this->triangle_grid_size);
this->lambda_c = 1.0f / (float)(this->mapCols-1);
this->lambda_r = 1.0f / (float)(this->mapRows-1);

// the scenegraph land 'upper' node
this->landTransform  = new ssgTransform ;
this->terrainRecenteringTransform = new ssgTransform;

createStates();

doCritical(li->mapProgress += 0.1f , li->cs);

#ifdef DEF_TERRAIN
// create tile transform grid
newSsgTransformMatrix(tileGrid,tile_grid_rows,tile_grid_columns,r_,c_);

// and set the right transform for each tile
setSsgTransformMatrix(tileGrid,tile_grid_rows,tile_grid_columns,gridStep,triangle_grid_size,rr_,cc_);

// fill the normals, colors etc matrix
fillAllMatrix();

// create tiles and attach them to the tile grid
createTiles();
#endif

#ifdef TRY_TERRAIN
tryBuildTerrain();
#endif 
}

Land::~Land()
{
//delete this->state;
//deleteMatrix(this->tileGrid,mapRows,i_);
}

void Land::createStates()
{
// new state
// new grass_state (grass with textures) 
grass_state    = new ssgSimpleState ;
grass_state -> setTexture		    ( li->textures[GRASS0_TEXTURE] ) ;
grass_state -> enable		    	( GL_TEXTURE_2D ) ;
grass_state -> enable		    	( GL_LIGHTING ) ;
grass_state -> setShadeModel   	( GL_SMOOTH ) ;
grass_state -> enable		    	( GL_COLOR_MATERIAL ) ;
grass_state -> enable			    ( GL_CULL_FACE      ) ;
grass_state -> setColourMaterial  ( GL_AMBIENT_AND_DIFFUSE ) ;
grass_state -> setMaterial		( GL_EMISSION, 0, 0, 0, 1 ) ;
grass_state -> setMaterial		( GL_SPECULAR, 0, 0, 0, 1 ) ;
grass_state -> setMaterial		( GL_DIFFUSE,  0, 0, 0, 1 ) ;
grass_state -> setMaterial		( GL_AMBIENT,  0, 0, 0, 1 ) ;
grass_state -> setShininess		( 0 ) ;
grass_state -> enable			( GL_BLEND ) ;

stones_state    = new ssgSimpleState ;
stones_state -> setTexture		    ( li->textures[STONES0_TEXTURE] ) ;
stones_state -> enable		    	( GL_TEXTURE_2D ) ;
stones_state -> enable		    	( GL_LIGHTING ) ;
stones_state -> setShadeModel   	( GL_SMOOTH ) ;
stones_state -> enable		    	( GL_COLOR_MATERIAL ) ;
stones_state -> enable			    ( GL_CULL_FACE      ) ;
stones_state -> setColourMaterial  ( GL_AMBIENT_AND_DIFFUSE ) ;
stones_state -> setMaterial		( GL_EMISSION, 0, 0, 0, 1 ) ;
stones_state -> setMaterial		( GL_SPECULAR, 0, 0, 0, 1 ) ;
stones_state -> setMaterial		( GL_DIFFUSE,  0, 0, 0, 1 ) ;
stones_state -> setMaterial		( GL_AMBIENT,  0, 0, 0, 1 ) ;
stones_state -> setShininess		( 0 ) ;
stones_state -> enable			( GL_BLEND ) ;
}

ssgSimpleState* Land::getState(int type)
{
ssgSimpleState *ss = NULL;

switch(type)
	{
	case GRASS_STATE:
		ss = grass_state;
		break;
	case STONES_STATE:
		ss = stones_state;
		break;
	default:
		break;
	}
return ss;
}

ssgTransform* Land::getTransform()
{
return this->landTransform;
}

void Land::fillAllMatrix()
{
time_t t = time ( NULL ) ;
printf("[%s] Filling matrices...\n", ctime ( & t ));

newSgVecXMatrix(normals,mapRows,mapCols,3,i_,j_);

for(int u = 0; u < mapRows-1; u++) // was mapRows
	{
	for(int w = 0; w < mapCols-1; w++) // was mapCols
		{
		// get the values, if there are not border points

			int xBL = mapRows - u - 1	;
			int yBL = w					;
			int xTL = mapRows - u - 2	;
			int yTL = w					;
			int xBR = mapRows - u - 1	;
			int yBR = w + 1				;
			int xTR = mapRows - u - 2	;
			int yTR = w + 1				;

			// get points
			float zzBL = landMap[xBL][yBL];
			float zzTL = landMap[xTL][yTL];
			float zzBR = landMap[xBR][yBR];
			float zzTR = landMap[xTR][yTR];

			
			// create vectors from points (needed for normals)
            sgVec3 pointBL;
			sgVec3 pointTL;
			sgVec3 pointBR;
			sgVec3 pointTR;

			sgSetVec3(pointBL,(float)yBL * gridStep,(float)(u) * gridStep,zzBL);
			sgSetVec3(pointTL,(float)yTL * gridStep,(float)(u+1) * gridStep,zzTL);
			sgSetVec3(pointBR,(float)yBR * gridStep,(float)(u) * gridStep,zzBR);
			sgSetVec3(pointTR,(float)yTR * gridStep,(float)(u+1) * gridStep,zzTR);

			// make normals
			sgVec3 normBL;
			sgVec3 normBR;
			sgVec3 normTL;
			sgVec3 normTR;

			sgMakeNormal(normBL,pointBL,pointBR,pointTL);	
			sgMakeNormal(normBR,pointBR,pointTR,pointBL);   
			sgMakeNormal(normTL,pointTL,pointBL,pointTR);   
			sgMakeNormal(normTR,pointTR,pointTL,pointBR);   

			interpolateNormal(normals,xBL,yBL,normBL);
			interpolateNormal(normals,xBR,yBR,normBR);
			interpolateNormal(normals,xTL,yTL,normTL);
			interpolateNormal(normals,xTR,yTR,normTR);
		}
	}
normaliseMatrix(normals,mapRows,mapCols,_lll,_llll);

// allocate a color matrix ( color per vertex )
newSgVecXMatrix(colors,mapRows,mapCols,4,ih_,jh_);

newSgVecXMatrix(bitmap,mapRows,mapCols,4,yh_,ty_);
newSgVecXMatrix(expo,mapRows,mapCols,4,fg_,sd_);
newSgVecXMatrix(shadow,mapRows,mapCols,4,kl_,ld_);

createColorMatrix(colors,normals);
createExpositionMatrix(expo,normals);
createBitmapMatrix(bitmap);
createShadowMatrix(colors,normals);

// if the object file is not present
if(!ulFileExists(obj_filename)) 
	{
	saveColorMatrix(bitmap);
	}
else 
	{
	loadObjectFile(colors);
	}
}

void Land::createTiles()
{
time_t t = time ( NULL ) ;
printf("[%s] Creating tiles...\n", ctime ( & t ));
ssgBranch *branch = new ssgBranch();

for(int i = 0; i < tile_grid_rows; i++)
	{
	for(int j = 0; j < tile_grid_columns; j++)
		{
		if(li->loadingType != BRIEF) tileGrid[i][j]->addKid(createTileAt(i,j));
		else tileGrid[i][j]->addKid(createLODTilesAt(i,j));
		tileGrid[i][j]->setName("TILE\0");
		branch -> addKid(tileGrid[i][j]);
		}
	}

//printf("Tile grid: %d %d\n",tile_grid_rows,tile_grid_columns);

// Now recenter the whole terrain to have his center in the origin
sgCoord terrainRecentering;
sgSetCoord (&terrainRecentering,- (float)this->online_terrain_range_x,- (float)this->online_terrain_range_y,0.0f,0.0f,0.0f,0.0f);
terrainRecenteringTransform->setTransform(&terrainRecentering);

// Rotate the terrain of 180∞, to match east and west
sgCoord terrainRotating;
sgSetCoord(&terrainRotating,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);

branch->setName("TILE_GRID\0");
this->terrainRecenteringTransform -> addKid( branch );
this->terrainRecenteringTransform -> setName("TERRAIN_RECENTERING_TRANSFORM\0");
this->landTransform->setTransform(&terrainRotating);
this->landTransform->setName("LAND_TRANSFORM\0");
this->landTransform->addKid(terrainRecenteringTransform);
}

ssgBranch* Land::createLODTilesAt(int y, int x)
{
// for each tile, create a ssgRangeSelector for different 
// detail levels
float rr[] = { LAND_RANGE_NEAR_VIEW, LAND_RANGE_MIDDLE_VIEW, LAND_RANGE_FAR_VIEW, LAND_RANGE_LIMIT_VIEW } ;

// lod = Level Of Detail
ssgRangeSelector *lod = new ssgRangeSelector () ;

// now it's time to create geometry

// BEWARE! negative values passed as third parameter are to 
// simulate the earth roundness!!! (And hide holes in the terrain
// for due to the minor number of triangles of far tiles)

// TRIANGLE_GRID_SIZE: take a point every ...  
lod  -> addKid ( createTilePortion ( x, y, LAND_NEAR_THIN_FACTOR,   0.0f   ) );
lod  -> addKid ( createTilePortion ( x, y, LAND_MIDDLE_THIN_FACTOR,   -5.0f ) ) ;
lod  -> addKid ( createTilePortion ( x, y, LAND_FAR_THIN_FACTOR,   -30.0f ) );
lod  -> setRanges ( rr, 4 ) ;

return lod;
}

ssgBranch* Land::createTilePortion(int x, int y, int tf, float z_down  )
{
int max_row;
int max_col;

ssgBranch *branch = new ssgBranch () ;

if( ((y+1) == tile_grid_rows) && (exceeding_r != 0) )
	max_row = exceeding_r;
else 
	max_row = triangle_grid_size;

if( ((x+1) == tile_grid_columns) && (exceeding_c != 0) )
	max_col = exceeding_c;
else 
	max_col = triangle_grid_size;

#ifdef SUPER_SPEED
ssgVertexArray *vl   = new ssgVertexArray(4);
ssgNormalArray *nl   = new ssgNormalArray(4);
ssgTexCoordArray *tl = new ssgTexCoordArray(4);
ssgColourArray *cl   = new ssgColourArray(4);
#endif


/*ssgSimpleState* state    = new ssgSimpleState ;
state -> setTexture		    ( li->textures[STONES0_TEXTURE] ) ;
state -> enable		    	( GL_TEXTURE_2D ) ;
state -> enable		    	( GL_LIGHTING ) ;
state -> setShadeModel   	( GL_SMOOTH ) ;
state -> enable		    	( GL_COLOR_MATERIAL ) ;
state -> enable			    ( GL_CULL_FACE      ) ;
state -> setColourMaterial  ( GL_AMBIENT_AND_DIFFUSE ) ;
state -> setMaterial		( GL_EMISSION, 0, 0, 0, 1 ) ;
state -> setMaterial		( GL_SPECULAR, 0, 0, 0, 1 ) ;
state -> setMaterial		( GL_DIFFUSE,  0, 0, 0, 1 ) ;
state -> setMaterial		( GL_AMBIENT,  0, 0, 0, 1 ) ;
state -> setShininess		( 0 ) ;
state -> enable			( GL_BLEND ) ;*/

for(int i = 0; i+tf-1 < max_col; i+=tf)
	{
	for(int j = 0; j+tf-1 < max_row; j+=tf)
		{
		// get the values, if there are not border points

			int xBL = mapRows - j - y*triangle_grid_size - 1	    ;
			int yBL = i + x*triangle_grid_size					    ;
			int xTL = mapRows - j - y*triangle_grid_size - 1 - tf	;
			int yTL = i + x*triangle_grid_size						;
			int xBR = mapRows - j - y*triangle_grid_size - 1		;
			int yBR = i + x*triangle_grid_size  + 0	+ tf			;
			int xTR = mapRows - j - y*triangle_grid_size - 1 - tf	;
			int yTR = i + x*triangle_grid_size  + 0	+ tf			;


			// get points
			float zzBL = landMap[xBL][yBL] + z_down;
			float zzTL = landMap[xTL][yTL] + z_down;
			float zzBR = landMap[xBR][yBR] + z_down;
			float zzTR = landMap[xTR][yTR] + z_down;

			// create vectors from points (needed for normals)
            sgVec3 pointBL;
			sgVec3 pointTL;
			sgVec3 pointBR;
			sgVec3 pointTR;

			sgSetVec3(pointBL,(float)i * gridStep ,(float)(j) * gridStep ,zzBL);
			sgSetVec3(pointTL,(float)i * gridStep ,(float)(j+tf) * gridStep ,zzTL);
			sgSetVec3(pointBR,(float)(i+tf) * gridStep ,(float)(j) * gridStep ,zzBR);
			sgSetVec3(pointTR,(float)(i+tf) * gridStep ,(float)(j+tf) * gridStep ,zzTR);

			// make normals
			sgVec3 normBL;
			sgVec3 normBR;
			sgVec3 normTL;
			sgVec3 normTR;

			sgCopyVec3(normBL,normals[xBL][yBL]);
			sgCopyVec3(normBR,normals[xBR][yBR]);
			sgCopyVec3(normTL,normals[xTL][yTL]);
			sgCopyVec3(normTR,normals[xTR][yTR]);

			// create colors (one per vertex)
			sgVec4 colorBL;
			sgVec4 colorBR;
			sgVec4 colorTL;
			sgVec4 colorTR;

			/*sgSetVec4(colorBL,LAND_GREEN);
			sgSetVec4(colorTL,LAND_GREEN);
			sgSetVec4(colorBR,LAND_GREEN);
			sgSetVec4(colorTR,LAND_GREEN);*/

			sgCopyVec4(colorBL,colors[xBL][yBL]);//LAND_GREEN);
			sgCopyVec4(colorTL,colors[xTL][yTL]);//LAND_GREEN);
			sgCopyVec4(colorBR,colors[xBR][yBR]);//LAND_GREEN);
			sgCopyVec4(colorTR,colors[xTR][yTR]);//LAND_GREEN);

			// set texture position
			sgVec2 textBL;
			sgVec2 textTL;
			sgVec2 textBR;
			sgVec2 textTR;

			if(1)//li->loadingType != BRIEF)
				{
				sgSetVec2(textBL,yBL*lambda_c,xBL*lambda_r);//0.0f,0.0f);
				sgSetVec2(textTL,yTL*lambda_c,xTL*lambda_r);//0.0f,1.0f);
				sgSetVec2(textBR,yBR*lambda_c,xBR*lambda_r);//1.0f,0.0f);
				sgSetVec2(textTR,yTR*lambda_c,xTR*lambda_r);//1.0f,1.0f);
				}
			else
				{
				sgSetVec2(textBL,0.0f,0.0f);
				sgSetVec2(textTL,0.0f,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR);
				sgSetVec2(textBR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR,0.0f);
				sgSetVec2(textTR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR);
				}

			// create vertex,colors,normals,textures lists!!!
			#ifdef LOW_SPEED
			ssgVertexArray *vl   = new ssgVertexArray(4);
			ssgNormalArray *nl   = new ssgNormalArray(4);
			ssgTexCoordArray *tl = new ssgTexCoordArray(4);
			ssgColourArray *cl   = new ssgColourArray(4);
			#endif

			// add all the sgVec*
			vl->add(pointBL);
			vl->add(pointBR);
			vl->add(pointTR);
			vl->add(pointTL);

			nl->add(normBL);
			nl->add(normBR);
			nl->add(normTR);
			nl->add(normTL);

			tl->add(textBL);
			tl->add(textBR);
			tl->add(textTR);
			tl->add(textTL);

			cl->add(colorBL);
			cl->add(colorBR);
			cl->add(colorTR);
			cl->add(colorTL);

			#ifdef LOW_SPEED
			// create a new vertex table
			ssgVtxTable *leaf = new ssgVtxTable(GL_QUADS,vl,nl,tl,cl);

			// set the leaf state
			leaf -> setState ( grass_state ) ;
			leaf -> setName  ("TERRAIN_LEAF\0");

			// attach it to the brach
			branch -> addKid( leaf );
			branch -> setName  ("TERRAIN_BRANCH\0");
			#endif
		}
	}

#ifdef SUPER_SPEED
// create a new vertex table
ssgVtxTable *leaf = new ssgVtxTable(GL_QUADS,vl,nl,tl,cl);

// set the leaf state
leaf -> setState ( grass_state ) ;
leaf -> setName  ("TERRAIN_LEAF\0");
// attach it to the brach
branch -> addKid( leaf );
branch -> setName  ("TERRAIN_BRANCH\0");
#endif

return branch;
}


ssgBranch* Land::createTileAt(int y, int x)
{
int max_row;
int max_col;

ssgBranch *branch = new ssgBranch () ;

if( ((y+1) == tile_grid_rows) && (exceeding_r != 0) )
	max_row = exceeding_r;
else 
	max_row = triangle_grid_size;

if( ((x+1) == tile_grid_columns) && (exceeding_c != 0) )
	max_col = exceeding_c;
else 
	max_col = triangle_grid_size;

#ifdef SUPER_SPEED
ssgVertexArray *vl   = new ssgVertexArray(4);
ssgNormalArray *nl   = new ssgNormalArray(4);
ssgTexCoordArray *tl = new ssgTexCoordArray(4);
ssgColourArray *cl   = new ssgColourArray(4);
#endif


/*ssgSimpleState* state    = new ssgSimpleState ;
state -> setTexture		    ( li->textures[STONES0_TEXTURE] ) ;
state -> enable		    	( GL_TEXTURE_2D ) ;
state -> enable		    	( GL_LIGHTING ) ;
state -> setShadeModel   	( GL_SMOOTH ) ;
state -> enable		    	( GL_COLOR_MATERIAL ) ;
state -> enable			    ( GL_CULL_FACE      ) ;
state -> setColourMaterial  ( GL_AMBIENT_AND_DIFFUSE ) ;
state -> setMaterial		( GL_EMISSION, 0, 0, 0, 1 ) ;
state -> setMaterial		( GL_SPECULAR, 0, 0, 0, 1 ) ;
state -> setMaterial		( GL_DIFFUSE,  0, 0, 0, 1 ) ;
state -> setMaterial		( GL_AMBIENT,  0, 0, 0, 1 ) ;
state -> setShininess		( 0 ) ;
state -> enable			( GL_BLEND ) ;*/
//printf("maxrow: %d\n",max_row);
//printf("maxcol: %d\n",max_col);

for(int i = 0; i < max_col; i++)
	{
	for(int j = 0; j < max_row; j++)
		{
		// get the values, if there are not border points

			int xBL = mapRows - j - y*triangle_grid_size - 1	;
			int yBL = i + x*triangle_grid_size					;
			int xTL = mapRows - j - y*triangle_grid_size - 2	;
			int yTL = i + x*triangle_grid_size					;
			int xBR = mapRows - j - y*triangle_grid_size - 1	;
			int yBR = i + x*triangle_grid_size  + 1				;
			int xTR = mapRows - j - y*triangle_grid_size - 2	;
			int yTR = i + x*triangle_grid_size  + 1				;


			// get points
			float zzBL = landMap[xBL][yBL];
			float zzTL = landMap[xTL][yTL];
			float zzBR = landMap[xBR][yBR];
			float zzTR = landMap[xTR][yTR];

			// create vectors from points (needed for normals)
            sgVec3 pointBL;
			sgVec3 pointTL;
			sgVec3 pointBR;
			sgVec3 pointTR;

			sgSetVec3(pointBL,(float)i * gridStep,(float)(j) * gridStep,zzBL);
			sgSetVec3(pointTL,(float)i * gridStep,(float)(j+1) * gridStep,zzTL);
			sgSetVec3(pointBR,(float)(i+1) * gridStep,(float)(j) * gridStep,zzBR);
			sgSetVec3(pointTR,(float)(i+1) * gridStep,(float)(j+1) * gridStep,zzTR);

			// make normals
			sgVec3 normBL;
			sgVec3 normBR;
			sgVec3 normTL;
			sgVec3 normTR;

			sgCopyVec3(normBL,normals[xBL][yBL]);
			sgCopyVec3(normBR,normals[xBR][yBR]);
			sgCopyVec3(normTL,normals[xTL][yTL]);
			sgCopyVec3(normTR,normals[xTR][yTR]);

			  // Now I calculate the terrain inclination... if more than
			  // a certain value, let there be rock!!!
			/*sgVec3 n_sum;
			sgZeroVec3(n_sum);
			sgAddVec3(n_sum,normBL);
			sgAddVec3(n_sum,normBR);
			sgAddVec3(n_sum,normTL);
			sgAddVec3(n_sum,normTR);
			sgNormalizeVec3(n_sum);
			sgVec3 n_temp;
			sgZeroVec3(n_temp);
			sgSetVec3(n_temp,n_sum[0],n_sum[1],0);
			sgNormalizeVec3(n_temp);
			sgFloat inclination = sgScalarProductVec3(n_temp,n_sum);

			int groundType;
			if(inclination >= LAND_MIN_INCLINATION_FOR_ROCKS)
				{
				groundType = ROCK_GROUND;
				//printf("Inclination = %.03f -> ROCKS\n",inclination);
				}
			else
				{
				groundType = SNOW_GROUND;
				//printf("Inclination = %.03f -> SNOW\n",inclination);
				}*/


			// create colors (one per vertex)
			sgVec4 colorBL;
			sgVec4 colorBR;
			sgVec4 colorTL;
			sgVec4 colorTR;

			sgCopyVec4(colorBL,colors[xBL][yBL]);//LAND_GREEN);
			sgCopyVec4(colorTL,colors[xTL][yTL]);//LAND_GREEN);
			sgCopyVec4(colorBR,colors[xBR][yBR]);//LAND_GREEN);
			sgCopyVec4(colorTR,colors[xTR][yTR]);//LAND_GREEN);

			// set texture position
			sgVec2 textBL;
			sgVec2 textTL;
			sgVec2 textBR;
			sgVec2 textTR;

			if(li->loadingType != BRIEF)
				{
				sgSetVec2(textBL,yBL*lambda_c,xBL*lambda_r);//0.0f,0.0f);
				sgSetVec2(textTL,yTL*lambda_c,xTL*lambda_r);//0.0f,1.0f);
				sgSetVec2(textBR,yBR*lambda_c,xBR*lambda_r);//1.0f,0.0f);
				sgSetVec2(textTR,yTR*lambda_c,xTR*lambda_r);//1.0f,1.0f);
				}
			else
				{
					sgSetVec2(textBL,0.0f,0.0f);
					sgSetVec2(textTL,0.0f,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR);
					sgSetVec2(textBR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR,0.0f);
					sgSetVec2(textTR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR,1.0f * LAND_TEXTURES_LAMBDA_MULT_FACTOR);
				}

			// create vertex,colors,normals,textures lists!!!
			#ifdef LOW_SPEED
			ssgVertexArray *vl   = new ssgVertexArray(4);
			ssgNormalArray *nl   = new ssgNormalArray(4);
			ssgTexCoordArray *tl = new ssgTexCoordArray(4);
			ssgColourArray *cl   = new ssgColourArray(4);
			#endif

			// add all the sgVec*
			vl->add(pointBL);
			vl->add(pointBR);
			vl->add(pointTR);
			vl->add(pointTR);
			vl->add(pointTL);
			vl->add(pointBL);

			nl->add(normBL);
			nl->add(normBR);
			nl->add(normTR);
			nl->add(normTR);
			nl->add(normTL);
			nl->add(normBL);

			tl->add(textBL);
			tl->add(textBR);
			tl->add(textTR);
			tl->add(textTR);
			tl->add(textTL);
			tl->add(textBL);

			cl->add(colorBL);
			cl->add(colorBR);
			cl->add(colorTR);
			cl->add(colorTR);
			cl->add(colorTL);
			cl->add(colorBL);

			#ifdef LOW_SPEED
			// create a new vertex table
			ssgVtxTable *leaf = new ssgVtxTable(GL_TRIANGLES,vl,nl,tl,cl);

			// set the leaf state
			leaf -> setState ( grass_state ) ;
			leaf -> setName  ("TERRAIN_LEAF\0");

			// attach it to the brach
			branch -> addKid( leaf );
			branch -> setName  ("TERRAIN_BRANCH\0");
			#endif
		}
	}

#ifdef SUPER_SPEED
// create a new vertex table
ssgVtxTable *leaf = new ssgVtxTable(GL_TRIANGLES,vl,nl,tl,cl);

// set the leaf state
leaf -> setState ( grass_state ) ;
leaf -> setName  ("TERRAIN_LEAF\0");
// attach it to the brach
branch -> addKid( leaf );
branch -> setName  ("TERRAIN_BRANCH\0");
#endif

return branch;
}

void Land::tryBuildTerrain()
{
// create the final ssgBranch()
ssgBranch *branch = new ssgBranch () ;

// create the sgVec* matrices... this is because I have to recompute each
// normal up to 4 times to find out the mean normal vector!!!
// This way I have one color, one vertex one texture one normal
// FOR EACH point of the land map!!!

newSgVecXMatrix(normals,mapRows,mapCols,3,i_,j_);

doCritical(li->mapProgress += 0.02f , li->cs);

int u = 0;
for(; u < mapRows-1; u++) // was mapRows
	{
	int w = 0;
	for(; w < mapCols-1; w++) // was mapCols
		{
		// get the values, if there are not border points

			int xBL = mapRows - u - 1	;
			int yBL = w					;
			int xTL = mapRows - u - 2	;
			int yTL = w					;
			int xBR = mapRows - u - 1	;
			int yBR = w + 1				;
			int xTR = mapRows - u - 2	;
			int yTR = w + 1				;

			// get points
			float zzBL = landMap[xBL][yBL];
			float zzTL = landMap[xTL][yTL];
			float zzBR = landMap[xBR][yBR];
			float zzTR = landMap[xTR][yTR];

			
			// create vectors from points (needed for normals)
            sgVec3 pointBL;
			sgVec3 pointTL;
			sgVec3 pointBR;
			sgVec3 pointTR;

			sgSetVec3(pointBL,(float)yBL * gridStep,(float)(u) * gridStep,zzBL);
			sgSetVec3(pointTL,(float)yTL * gridStep,(float)(u+1) * gridStep,zzTL);
			sgSetVec3(pointBR,(float)yBR * gridStep,(float)(u) * gridStep,zzBR);
			sgSetVec3(pointTR,(float)yTR * gridStep,(float)(u+1) * gridStep,zzTR);

			// make normals
			sgVec3 normBL;
			sgVec3 normBR;
			sgVec3 normTL;
			sgVec3 normTR;

			sgMakeNormal(normBL,pointBL,pointBR,pointTL);	//sgNormaliseVec3(normBL);
			sgMakeNormal(normBR,pointBR,pointTR,pointBL);   //sgNormaliseVec3(normBR);
			sgMakeNormal(normTL,pointTL,pointBL,pointTR);   //sgNormaliseVec3(normTL);
			sgMakeNormal(normTR,pointTR,pointTL,pointBR);   //sgNormaliseVec3(normTR);

			interpolateNormal(normals,xBL,yBL,normBL);
			interpolateNormal(normals,xBR,yBR,normBR);
			interpolateNormal(normals,xTL,yTL,normTL);
			interpolateNormal(normals,xTR,yTR,normTR);
		}
	float pr = 0.07f * ((float)(u*w)/(float)((mapRows-1)*(mapCols-1)));
	doCritical(li->mapProgress += pr, li->cs);
	}
normaliseMatrix(normals,mapRows,mapCols,_lll,_llll);



// allocate a color matrix ( color per vertex )
newSgVecXMatrix(colors,mapRows,mapCols,4,ih_,jh_);
newSgVecXMatrix(bitmap,mapRows,mapCols,4,yh_,ty_);
newSgVecXMatrix(expo,mapRows,mapCols,4,fg_,sd_);

createColorMatrix(colors,normals);
createExpositionMatrix(expo,normals);
createBitmapMatrix(bitmap);
//saveExpositionMatrix(expo);

// if the object file is not present
if(!ulFileExists(obj_filename)) 
	{
	//createBitmapMatrix(bitmap);
	saveColorMatrix(bitmap);
	//saveColorMatrix(colors);
	}
else 
	{
	loadObjectFile(colors);
	}

doCritical(li->mapProgress += 0.12f , li->cs);

/*			ssgVertexArray *vl   = new ssgVertexArray(4);
			ssgNormalArray *nl   = new ssgNormalArray(4);
			ssgTexCoordArray *tl = new ssgTexCoordArray(4);
			ssgColourArray *cl   = new ssgColourArray(4);*/
int j = 0;
for(; j < mapRows-1; j++) // was mapRows
	{
	int i = 0;
	for(; i < mapCols-1; i++) // was mapCols
		{
		// get the values, if there are not border points

			int xBL = mapRows - j - 1	;
			int yBL = i					;
			int xTL = mapRows - j - 2	;
			int yTL = i					;
			int xBR = mapRows - j - 1	;
			int yBR = i + 1				;
			int xTR = mapRows - j - 2	;
			int yTR = i + 1				;


			// get points
			float zzBL = landMap[xBL][yBL];
			float zzTL = landMap[xTL][yTL];
			float zzBR = landMap[xBR][yBR];
			float zzTR = landMap[xTR][yTR];

			// create vectors from points (needed for normals)
            sgVec3 pointBL;
			sgVec3 pointTL;
			sgVec3 pointBR;
			sgVec3 pointTR;

			sgSetVec3(pointBL,(float)yBL * gridStep,(float)(j) * gridStep,zzBL);
			sgSetVec3(pointTL,(float)yTL * gridStep,(float)(j+1) * gridStep,zzTL);
			sgSetVec3(pointBR,(float)yBR * gridStep,(float)(j) * gridStep,zzBR);
			sgSetVec3(pointTR,(float)yTR * gridStep,(float)(j+1) * gridStep,zzTR);

			// make normals
			sgVec3 normBL;
			sgVec3 normBR;
			sgVec3 normTL;
			sgVec3 normTR;

			sgCopyVec3(normBL,normals[xBL][yBL]);
			sgCopyVec3(normBR,normals[xBR][yBR]);
			sgCopyVec3(normTL,normals[xTL][yTL]);
			sgCopyVec3(normTR,normals[xTR][yTR]);

			// create colors (one per vertex)
			sgVec4 colorBL;
			sgVec4 colorBR;
			sgVec4 colorTL;
			sgVec4 colorTR;

			sgCopyVec4(colorBL,colors[xBL][yBL]);//LAND_GREEN);
			sgCopyVec4(colorTL,colors[xTL][yTL]);//LAND_GREEN);
			sgCopyVec4(colorBR,colors[xBR][yBR]);//LAND_GREEN);
			sgCopyVec4(colorTR,colors[xTR][yTR]);//LAND_GREEN);

			// set texture position
			sgVec2 textBL;
			sgVec2 textTL;
			sgVec2 textBR;
			sgVec2 textTR;

			sgSetVec2(textBL,0.0f,0.0f);
			sgSetVec2(textTL,0.0f,1.0f);
			sgSetVec2(textBR,1.0f,0.0f);
			sgSetVec2(textTR,1.0f,1.0f);

			// create vertex,colors,normals,textures lists!!!
			ssgVertexArray *vl   = new ssgVertexArray(4);
			ssgNormalArray *nl   = new ssgNormalArray(4);
			ssgTexCoordArray *tl = new ssgTexCoordArray(4);
			ssgColourArray *cl   = new ssgColourArray(4);

			// add all the sgVec*
			vl->add(pointBL);
			vl->add(pointBR);
			vl->add(pointTR);
			vl->add(pointTL);

			nl->add(normBL);
			nl->add(normBR);
			nl->add(normTR);
			nl->add(normTL);

			tl->add(textBL);
			tl->add(textBR);
			tl->add(textTR);
			tl->add(textTL);

			cl->add(colorBL);
			cl->add(colorBR);
			cl->add(colorTR);
			cl->add(colorTL);

			// create a new vertex table
			ssgVtxTable *leaf = new ssgVtxTable(GL_TRIANGLE_FAN,vl,nl,tl,cl);

			// set the leaf state
			//leaf -> setState ( state ) ;
			leaf -> setName  ("TERRAIN_LEAF\0");

			// attach it to the brach
			branch -> addKid( leaf );
			branch -> setName("TERRAIN_BRANCH\0");
		}
	float pr2 = 0.70f * ((float)(i*j)/(float)((mapRows-1)*(mapCols-1)));
	doCritical(li->mapProgress += pr2, li->cs);
	}

	// Now recenter the whole terrain to have his center in the origin
	sgCoord terrainRecentering;
	sgSetCoord (&terrainRecentering,- (float)this->online_terrain_range_x,- (float)this->online_terrain_range_y,0.0f,0.0f,0.0f,0.0f);
	terrainRecenteringTransform->setTransform(&terrainRecentering);

	// Rotate the terrain of 180∞, to match east and west
	sgCoord terrainRotating;
	sgSetCoord(&terrainRotating,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);

	this->terrainRecenteringTransform -> addKid( branch );
	this->landTransform->setTransform(&terrainRotating);
	this->landTransform->addKid(terrainRecenteringTransform);

	doCritical(li->mapProgress += 1.0f , li->cs);

//landTransform -> addKid( branch );
}

void Land::createColorMatrix(float ***colors, float ***normals)
{
srand( (unsigned)time( NULL ) );

	
for(int i = 0; i < mapRows; i++)
	{
	for(int j = 0; j < mapCols; j++)
		{

		// Now I calculate the terrain inclination... if more than
		// a certain value, let there be rock!!!
		sgVec3 n_temp;
		sgSetVec3(n_temp,normals[i][j][0],normals[i][j][1],0.0f);
		sgNormalizeVec3(n_temp);
		sgFloat inclination = sgScalarProductVec3(n_temp,normals[i][j]);

		if(inclination > LAND_MIN_INCLINATION_FOR_ROCKS)
			{
			sgSetVec4(colors[i][j],LAND_STONEGRAY);
			/*int e;
			throwDice(e,4);
			if( e == 0)
				sgSetVec4(colors[i][j],LAND_GRAY);
			else if( e == 1 )
				sgSetVec4(colors[i][j],LAND_GRAY1);
			else if( e == 2 )
				sgSetVec4(colors[i][j],LAND_GRAY2);
			else if( e == 3)
				sgSetVec4(colors[i][j],LAND_GRAY3);*/
			}
		else if(landMap[i][j] > LAND_SNOWY_MOUNTAINS_COLOUR)
			{
			sgSetVec4(colors[i][j],LAND_HIGHICE);
			//sgSetVec4(colors[i][j],LAND_ICE);
			}
		else if(landMap[i][j] > LAND_MOUNTAINS_COLOR)
			{
			sgSetVec4(colors[i][j],LAND_GRAYGREEN);
			/*int f;
			throwDice(f,4);
			if( f == 0)
				sgSetVec4(colors[i][j],LAND_ICE);
			else if( f == 1 )
				sgSetVec4(colors[i][j],LAND_GREEN);
			else if( f == 2 )
				sgSetVec4(colors[i][j],LAND_ICE);
			else if( f == 3)
				sgSetVec4(colors[i][j],LAND_DARK3);*/
			}
		else if(landMap[i][j] > LAND_HIGH_HILLS_COLOR)
			{
			sgSetVec4(colors[i][j],LAND_BROWNGREEN);
			}
		else if(landMap[i][j] > LAND_LOW_HILLS_COLOR)
			{
			sgSetVec4(colors[i][j],LAND_OLIVEBROWN);
			}
		else if(landMap[i][j] > LAND_HIGH_PLAINS_COLOR)
			{
			sgSetVec4(colors[i][j],LAND_DARKGREEN);
			}
		else if(landMap[i][j] > LAND_LOW_PLAINS_COLOR)
			{
			sgSetVec4(colors[i][j],LAND_DARKESTGREEN);
			}
		else if(inclination > LAND_MIN_INCLINATION_FOR_HILLS)
			{
			int f;
			throwDice(f,4);
			if( f == 0)
				sgSetVec4(colors[i][j],LAND_DARK);
			else if( f == 1 )
				sgSetVec4(colors[i][j],LAND_DARK1);
			else if( f == 2 )
				sgSetVec4(colors[i][j],LAND_DARK2);
			else if( f == 3)
				sgSetVec4(colors[i][j],LAND_DARK3);
			}
		else
			{
			int d;
			throwDice(d,4);
			if( d == 0)
				sgSetVec4(colors[i][j],LAND_GREEN);
			else if( d == 1 )
				sgSetVec4(colors[i][j],LAND_GREEN1);
			else if( d == 2 )
				sgSetVec4(colors[i][j],LAND_GREEN2);
			else if( d == 3)
				sgSetVec4(colors[i][j],LAND_GREEN3);
			//sgCopyVec4(colors[i][j],getHeigthColor(landMap[i][j]));
			}
		}
	}

}

void Land::createBitmapMatrix(float ***colors)
{
sgVec3 light;
sgFloat scalar;
sgSetVec3(light,1.0f,1.0f,0.5f);
sgNormaliseVec3(light);

for(int i = 0; i < mapRows; i++)
	{
	for(int j = 0; j < mapCols; j++)
		{
		float *vec;
		
		scalar = sgScalarProductVec3(normals[i][j],light);
		scalar += 1.0f;
		scalar /= 2.0f;
		
		vec = getHeigthColor(landMap[i][j]);

		vec[0] *= scalar;
		vec[1] *= scalar;
		vec[2] *= scalar;

		sgCopyVec4(colors[i][j],vec);
		free(vec);
		}
	}
}

void Land::createExpositionMatrix(float ***em, float ***n)
{
sgVec3 light;
sgFloat scalar;
sgSetVec3(light,1.0f,0.0f,1.0f);
sgNormaliseVec3(light);

for(int i = 0; i < mapRows; i++)
	{
	for(int j = 0; j < mapCols; j++)
		{
		scalar = sgScalarProductVec3(n[i][j],light);
		scalar += 1.0f;
		scalar /= 2.0f;
		
		if(n[i][j][1] >= 0.0f)
			{
			sgSetVec4(em[i][j],LAND_BLUE);
			}
		else
			{
			sgSetVec4(em[i][j],LAND_RED);
			}

		em[i][j][0] *= scalar;
		em[i][j][1] *= scalar;
		em[i][j][2] *= scalar;

		}
	}
}

float* Land::getHeigthColor(float h)
{
int c = (int)((h / MAX_HEIGTH) * (float)(NUM_MAP_COLS-1));
float *cv = (float*)malloc(4*sizeof(float));

sgCopyVec4(cv,heightColors[c]);

return cv;
}

void Land::createShadowMatrix(float ***c, float ***n)
{
sgVec3 light;
sgFloat scalar;
sgSetVec3(light,1.0f,1.0f,0.5f);
sgNormaliseVec3(light);
	
for(int i = 0; i < mapRows; i++)
	{
	for(int j = 0; j < mapCols; j++)
		{
		scalar = sgScalarProductVec3(n[i][j],light);
		scalar += 1.0f;
		scalar /= 2.0f;
		
		this->shadow[i][j][0] = c[i][j][0] * scalar;
		this->shadow[i][j][1] = c[i][j][1] * scalar;
		this->shadow[i][j][2] = c[i][j][2] * scalar;
		this->shadow[i][j][3] = 1.0f;//c[i][j][3];
		}
	}
}

float*** Land::getShadowMatrix()
{
return this->shadow;
}

GLubyte* Land::createPrintableMap(float*** cm)
{
int i,j,k;
int w = mapCols;
int h = mapRows;
int scan_line_completion = 0;
int alpha_scan_line_completionrection = 0;
int zero_padding = w%4;
GLubyte* outbits;
int bitsize = ((((w * 24) + 31) & ~31) >> 3) * h;
//printf("mapCols : %d, mapRows : %d, bitsize : %d [%d %d]\n",mapCols,mapRows,bitsize,bitsize/4,bitsize%4);
//exit(0);

if ((outbits = (GLubyte*)malloc(bitsize)) == NULL)
        {
        return NULL;
        }

/* Zeros in bits */
for(k = 0; k < bitsize; k++)
{
      outbits[k] = (GLubyte)0; //printf("%d\n",k);
}

GLubyte a,b,c;

for(j = 0; j < h; j++)
     {
     for(i = 0; i < w; i += 1)
           {
           a = outbits[i*3+0+scan_line_completion+j*w*3] = (GLubyte)(cm[h-j-1][i][2] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           b = outbits[i*3+1+scan_line_completion+j*w*3] = (GLubyte)(cm[h-j-1][i][1] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           c = outbits[i*3+2+scan_line_completion+j*w*3] = (GLubyte)(cm[h-j-1][i][0] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           alpha_scan_line_completionrection++;
           }
     scan_line_completion += zero_padding;
     //alpha_scan_line_completionrection = 0;
     }

/*for(int y = 0; y < bitsize; y++)
{
      printf("%d\n",outbits[y]);
}*/

return outbits;
}

/*
 * 'SaveDIBitmap()' - Save a DIB/BMP file to disk.
 *
 * Returns 1 on success or 0 on failure...
 */

int Land::saveColorMatrix(float ***cm)
{
    FILE             *fp;          /* Open file pointer */
    GLubyte          *outs;        /* Bytes to be written */

	int w = mapCols;
	int h = mapRows;

	BITMAPFILEHEADER header;
	BITMAPINFO info;

    outs = createPrintableMap(cm);

	
	//return(1);

    /* Try opening the file; use "wb" mode to write this *binary* file. */
    if ((fp = fopen(obj_filename, "wb")) == NULL)
		{
		printf("Can't open File\n");
        return (0);
		}

    /* Figure out the bitmap size */
	int bitsize = ((((w * 24) + 31) & ~31) >> 3) * h;
	
	info.bmiHeader.biBitCount  = 24;
	info.bmiHeader.biSize      = 40;	
    info.bmiHeader.biCompression = BI_RGB;
	info.bmiHeader.biSizeImage = bitsize;
	info.bmiHeader.biWidth =  w;
	info.bmiHeader.biHeight = h;
	info.bmiHeader.biPlanes = 1;
	info.bmiHeader.biClrUsed = 0;
	info.bmiHeader.biClrImportant = 0;
	info.bmiHeader.biXPelsPerMeter = 0;
	info.bmiHeader.biYPelsPerMeter = 0;


    /* Figure out the header size */
    int infosize = sizeof(BITMAPINFOHEADER);


    int size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;

    /* Write the file header, bitmap information, and bitmap pixel data... */
    header.bfType      = BF_TYPE; /* Non-portable... sigh MB*/
    header.bfSize      = size;
    header.bfReserved1 = 0;
    header.bfReserved2 = 0;
    header.bfOffBits   = sizeof(BITMAPFILEHEADER) + infosize;

    if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
        {
        /* Couldn't write the file header - return... */
		printf("Couldn't write the file header\n");
        fclose(fp);
        return (0);
        }

    if (fwrite(&info, 1, infosize, fp) < infosize)
        {
        /* Couldn't write the bitmap header - return... */
		printf("Couldn't write the bitmap header\n");
        fclose(fp);
        return (0);
        }

    if (fwrite(outs, 1, bitsize, fp) < bitsize)
        {
        /* Couldn't write the bitmap - return... */
		printf("Couldn't write the bitmap\n");
        fclose(fp);
        return (0);
        }

  /*   OK, everything went fine - return... */
    fclose(fp);
    free(outs);
    return (1);
}

int Land::loadObjectFile(float*** cm)
{
    FILE             *fp;          /* Open file pointer */
	BITMAPFILEHEADER header;
	BITMAPINFO       *info;
	int				 bitsize;
	GLubyte*         bits;


    /* Try opening the file; use "rb" mode to read this *binary* file. */
    if ((fp = fopen(obj_filename, "rb")) == NULL)
        {
        printf("File %s not found...\n",obj_filename);
        return (0); 
        }

    /* Read the file header and any following bitmap information... */
    if (fread(&header, sizeof(BITMAPFILEHEADER), 1, fp) < 1)
        {
        /* Couldn't read the file header - return NULL... */
		printf("Couldn't read the file header\n");
	    fclose(fp);
        return (0);
        }

    if (header.bfType != BF_TYPE)	/* Check for BM reversed... */
        {
        /* Not a bitmap file - return NULL... */
		printf("Not a bitmap file\n");
        fclose(fp);
        return (0);
        }

    int infosize = header.bfOffBits - sizeof(BITMAPFILEHEADER);
    if ((info = (BITMAPINFO *)malloc(infosize)) == NULL)
        {
        /* Couldn't allocate memory for bitmap info - return NULL... */
		printf("Couldn't allocate memory for bitmap info\n");
        fclose(fp);
        return (0);
        }

    if (fread(info, 1, infosize, fp) < infosize)
        {
        /* Couldn't read the bitmap header - return NULL... */
		printf("Couldn't read the bitmap header\n");
        free(info);
        fclose(fp);
        return (0);
        }

    /* Now that we have all the header info read in, allocate memory for *
     * the bitmap and read *it* in...                                    */
    if ((bitsize = (info)->bmiHeader.biSizeImage) == 0)
        bitsize = ((info)->bmiHeader.biWidth *
                   (info)->bmiHeader.biBitCount + 7) / 8 *
  	           abs((info)->bmiHeader.biHeight);

    if ((bits = (GLubyte*)malloc(bitsize)) == NULL)
        {
        /* Couldn't allocate memory - return NULL! */
		printf("Couldn't allocate memory\n");
        free(info);
        fclose(fp);
        return (0);
        }

    if (fread(bits, 1, bitsize, fp) < bitsize)
        {
        /* Couldn't read bitmap - free memory and return NULL! */
		printf("Couldn't read bitmap\n");
        free(info);
        free(bits);
        fclose(fp);
        return (0);
        }

    /* OK, everything went fine - return the allocated bitmap... */
    fclose(fp);
    loadObjects(cm,bits);
    return (1);
}

void Land::loadObjects(float*** cm, GLubyte* bits)
{
int i;
int j;
int h = mapRows;
int w = mapCols;

int scan_line_completion = 0;
int alpha_scan_line_completionrection = 0;
int zero_padding = w%4;

float red,green,blue,alpha;
red   = 0.0f;
green = 0.0f;
blue  = 0.0f;
alpha = 1.0f;

for(j = 0; j < h; j++)
     {
     for(i = 0; i < w; i += 1)
           {
           blue   = ((float)bits[i*3+0+scan_line_completion+j*w*3])/255.0f; //= (GLubyte)(cm[h-j-1][i][2] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           green  = ((float)bits[i*3+1+scan_line_completion+j*w*3])/255.0f; //= (GLubyte)(cm[h-j-1][i][1] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           red    = ((float)bits[i*3+2+scan_line_completion+j*w*3])/255.0f; //= (GLubyte)(cm[h-j-1][i][0] * 255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
			
		   sgVec4 cc;
		   sgSetVec4(cc,red,green,blue,alpha);

		   if(sgEqualVec4(cc,pixelColors[LAND_FOREST]))
				{
			    sgCopyVec4(cm[h-j-1][i],objectsColors[LAND_FOREST]);
				}
		   else if(sgEqualVec4(cc,pixelColors[LAND_RIVER]))
				{
			    sgCopyVec4(cm[h-j-1][i],objectsColors[LAND_RIVER]);
				}
		   else if(sgEqualVec4(cc,pixelColors[LAND_MUD]))
				{
			    sgCopyVec4(cm[h-j-1][i],objectsColors[LAND_MUD]);
				}
	   
		   alpha_scan_line_completionrection++;
           }
     scan_line_completion += zero_padding;
     }
}

int Land::saveExpositionMatrix(float ***cm)
{
    FILE             *fp;          /* Open file pointer */
    GLubyte          *outs;        /* Bytes to be written */

	int w = mapCols;
	int h = mapRows;

	BITMAPFILEHEADER header;
	BITMAPINFO info;

    outs = createPrintableMap(cm);

	
	//return(1);

    /* Try opening the file; use "wb" mode to write this *binary* file. */
    if ((fp = fopen("./exposition.bmp", "wb")) == NULL)
		{
		printf("Can't open File\n");
        return (0);
		}

    /* Figure out the bitmap size */
	int bitsize = ((((w * 24) + 31) & ~31) >> 3) * h;
	
	info.bmiHeader.biBitCount  = 24;
	info.bmiHeader.biSize      = 40;	
    info.bmiHeader.biCompression = BI_RGB;
	info.bmiHeader.biSizeImage = bitsize;
	info.bmiHeader.biWidth =  w;
	info.bmiHeader.biHeight = h;
	info.bmiHeader.biPlanes = 1;
	info.bmiHeader.biClrUsed = 0;
	info.bmiHeader.biClrImportant = 0;
	info.bmiHeader.biXPelsPerMeter = 0;
	info.bmiHeader.biYPelsPerMeter = 0;


    /* Figure out the header size */
    int infosize = sizeof(BITMAPINFOHEADER);


    int size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;

    /* Write the file header, bitmap information, and bitmap pixel data... */
    header.bfType      = BF_TYPE; /* Non-portable... sigh MB*/
    header.bfSize      = size;
    header.bfReserved1 = 0;
    header.bfReserved2 = 0;
    header.bfOffBits   = sizeof(BITMAPFILEHEADER) + infosize;

    if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
        {
        /* Couldn't write the file header - return... */
		printf("Couldn't write the file header\n");
        fclose(fp);
        return (0);
        }

    if (fwrite(&info, 1, infosize, fp) < infosize)
        {
        /* Couldn't write the bitmap header - return... */
		printf("Couldn't write the bitmap header\n");
        fclose(fp);
        return (0);
        }

    if (fwrite(outs, 1, bitsize, fp) < bitsize)
        {
        /* Couldn't write the bitmap - return... */
		printf("Couldn't write the bitmap\n");
        fclose(fp);
        return (0);
        }

  /*   OK, everything went fine - return... */
    fclose(fp);
    free(outs);
    return (1);
}

int Land::getHeigth()
{
return this->mapRows;
}

int Land::getWidth()
{
return this->mapCols;
}

float*** Land::getLevelsMatrix()
{
//printSgVec3Matrix(this->bitmap,mapRows,mapCols,1,i,j);
return this->bitmap;
}

float*** Land::getExpoMatrix()
{
return this->expo;
}

float*** Land::getColorsMatrix()
{
return this->colors;
}

void Land::freeAllMatrix()
{
deleteSgVecXMatrix(shadow,mapRows,mapCols,i4_,j4_);
deleteSgVecXMatrix(expo,mapRows,mapCols,i5_,j5_);
deleteSgVecXMatrix(bitmap,mapRows,mapCols,i_,j_);

deleteSgVecXMatrix(colors,mapRows,mapCols,i2_,j2_);
deleteMatrix(landMap,mapRows,mapCols);
deleteSgVecXMatrix(normals,mapRows,mapCols,i3_,j3_);
}

float Land::getXCorrection()
{
return - (this->online_terrain_range_x + this->x_start_coord);
}

float Land::getYCorrection()
{
return - (this->online_terrain_range_y + this->y_start_coord);
}

void Land::setWireframe(int s)
{
//printf("wireframe is %d\n",s);
wire_update(this->terrainRecenteringTransform,s);
}

void Land::addWorld(char filename[])
{

}

ssgTransform* Land::getRepositionTransform()
{
return this->terrainRecenteringTransform;
}

float Land::getStartE()
{
return (float)x_start_coord;
}

float Land::getStartN()
{
return (float)y_start_coord;
}

float Land::reposition(Land *mainLand, int where, float y)
{
ssgTransform* tr = mainLand->getRepositionTransform();
sgMat4 rm;
tr->getTransform(rm);

float mainX = rm[3][0];
float mainY = rm[3][1];

printf("MAIN : %f %f\n",mainX,mainY);

float thisX = 0.0f;
float thisY = 0.0f;


switch(where)
	{
	case WEST:
			thisX = -(this->online_terrain_range_x*2.0) + mainX; //-11000.0f
			thisY = mainY + y;
			printf("WEST: %f %f\n",this->online_terrain_range_x,mainX);
			printf("%d %d\n",mapRows,mapCols);
	break;
	case SOUTH:
			thisX = -(this->online_terrain_range_x); 
			thisY = - this->online_terrain_range_y + 2.0f*mainY;
			printf("SOUTH: %f %f\n",thisX,thisY);
	break;
	case NORTH:
			thisX = -(this->online_terrain_range_x); 
			thisY = - mainY;
			printf("NORTH: %f %f\n",thisX,thisY);
	break;
	case EAST:
			thisX = - mainX;
			thisY = mainY + y;
			printf("EAST: %f %f\n",thisX,thisY);
	break;
	default:
	break;
	}

sgMat4 final_rep;
sgMakeIdentMat4(final_rep);
final_rep[3][0] = thisX; 
final_rep[3][1] = thisY;

this->terrainRecenteringTransform->setTransform(final_rep);

return thisY - mainY;
}



static int wire_draw ( ssgEntity* e )
{
  if ( e -> isAKindOf ( ssgTypeLeaf() ) )
  {
    ssgLeaf* leaf = (ssgLeaf*) e ;
    leaf -> drawHighlight ( wire_colour ) ;
  }
  return 1 ;
}


static void wire_update ( ssgEntity *e, int flag )
{
  if ( e -> isAKindOf ( ssgTypeBranch() ) )
  {
    ssgBranch *br = (ssgBranch *) e ;
    
    for ( int i = 0 ; i < br -> getNumKids () ; i++ )
      wire_update ( br -> getKid ( i ), flag ) ;
  }
  else if ( e -> isAKindOf ( ssgTypeLeaf() ) )
  {
    ssgLeaf* leaf = (ssgLeaf *) e ;
    leaf -> setCallback ( SSG_CALLBACK_POSTDRAW, flag? wire_draw: NULL ) ;
  }
}